/*!
 * \file ParserCTPOpt.cpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief CTP期权行情解析器实现文件
 * 
 * \details 该文件实现了ParserCTPOpt类的所有功能，包括：
 *          - CTP期权行情API的初始化和连接管理
 *          - 期权行情数据的接收、转换和分发
 *          - 用户登录认证和会话管理
 *          - 期权合约订阅和退订管理
 *          - 期权夜盘时间处理和数据校验
 *          - 错误处理和异常情况的处理
 *          - 与WonderTrader框架的期权数据格式转换
 *          - 针对期权市场特殊性的专门处理逻辑
 */
#include "ParserCTPOpt.h"

#include "../Includes/WTSDataDef.hpp"
#include "../Includes/WTSContractInfo.hpp"
#include "../Includes/WTSVariant.hpp"
#include "../Includes/IBaseDataMgr.h"

#include "../Share/TimeUtils.hpp"
#include "../Share/StdUtils.hpp"
#include "../Share/ModuleHelper.hpp"

#include <boost/filesystem.hpp>

// By Wesley @ 2022.01.05
#include "../Share/fmtlib.h"

/*!
 * \brief 写入日志的模板函数
 * \tparam Args 可变参数类型
 * \param sink 日志接收器指针
 * \param ll 日志级别
 * \param format 格式化字符串
 * \param args 可变参数列表
 * 
 * 使用fmt库进行格式化的线程安全日志写入函数
 */
template<typename... Args>
inline void write_log(IParserSpi* sink, WTSLogLevel ll, const char* format, const Args&... args)
{
	if (sink == NULL)
		return;

	static thread_local char buffer[512] = { 0 };
	memset(buffer, 0, 512);
	fmt::format_to(buffer, format, args...);

	sink->handleParserLog(ll, buffer);
}

/*!
 * \brief C接口导出函数
 * 
 * 提供给外部动态加载的标准C接口
 */
extern "C"
{
	/*!
	 * \brief 创建解析器实例
	 * \return 解析器实例指针
	 * 
	 * 工厂函数，创建ParserCTPOpt实例
	 */
	EXPORT_FLAG IParserApi* createParser()
	{
		ParserCTPOpt* parser = new ParserCTPOpt();
		return parser;
	}

	/*!
	 * \brief 销毁解析器实例
	 * \param parser 解析器实例指针的引用
	 * 
	 * 安全销毁解析器实例，避免内存泄漏
	 */
	EXPORT_FLAG void deleteParser(IParserApi* &parser)
	{
		if (NULL != parser)
		{
			delete parser;
			parser = NULL;
		}
	}
};

/*!
 * \brief 时间字符串转换为整数
 * \param strTime 时间字符串（格式：HH:MM:SS）
 * \return 时间整数（格式：HHMMSS）
 * 
 * 将CTP期权返回的时间字符串格式转换为WonderTrader使用的时间整数格式
 */
uint32_t strToTime(const char* strTime)
{
	std::string str;
	const char *pos = strTime;
	while(strlen(pos) > 0)
	{
		if(pos[0] != ':')
		{
			str.append(pos, 1);
		}
		pos++;
	}

	return strtoul(str.c_str(), NULL, 10);
}

/*!
 * \brief 检查数值有效性
 * \param val 待检查的数值
 * \return 有效的数值，无效时返回0
 * 
 * 检查CTP期权返回的价格数据是否有效，过滤掉无效的最大值
 * 对于期权，需要特别处理可能为0的合理价格
 */
inline double checkValid(double val)
{
	if (val == DBL_MAX || val == FLT_MAX)
		return 0;

	return val;
}

ParserCTPOpt::ParserCTPOpt()
	:m_pUserAPI(NULL)
	,m_iRequestID(0)
	,m_uTradingDate(0)
	,m_bLocalTime(false)
{
}


ParserCTPOpt::~ParserCTPOpt()
{
	m_pUserAPI = NULL;
}

bool ParserCTPOpt::init(WTSVariant* config)
{
	// 读取配置参数
	m_strFrontAddr = config->getCString("front");
	m_strBroker = config->getCString("broker");
	m_strUserID = config->getCString("user");
	m_strPassword = config->getCString("pass");
	m_bLocalTime = config->getBoolean("localtime");
	m_strFlowDir = config->getCString("flowdir");

	// 设置默认流文件目录
	if (m_strFlowDir.empty())
		m_strFlowDir = "CTPOptMDFlow";

	m_strFlowDir = StrUtil::standardisePath(m_strFlowDir);

	// 读取CTP期权模块名称，默认使用标准CTP期权模块
	std::string module = config->getCString("ctpmodule");
	if (module.empty())
		module = "soptthostmduserapi_se";
	
	// 加载CTP期权动态库
	std::string dllpath = getBinDir() + DLLHelper::wrap_module(module.c_str(), "");
	m_hInstCTP = DLLHelper::load_library(dllpath.c_str());
	
	// 创建流文件目录
	std::string path = StrUtil::printf("%s/%s/%s/", m_strFlowDir.c_str(), m_strBroker.c_str(), m_strUserID.c_str());
	if (!StdFile::exists(path.c_str()))
	{
		boost::filesystem::create_directories(boost::filesystem::path(path));
	}
	
	// 获取CTP期权API创建函数（跨平台符号名称处理）
#ifdef _WIN32
#	ifdef _WIN64
	const char* creatorName = "?CreateFtdcMdApi@CThostFtdcMdApi@ctp_sopt@@SAPEAV12@PEBD_N1@Z";
#	else
	const char* creatorName = "?CreateFtdcMdApi@CThostFtdcMdApi@ctp_sopt@@SAPAV12@PBD_N1@Z";
#	endif
#else
	const char* creatorName = "_ZN8ctp_sopt15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb";
#endif
	
	// 创建CTP期权行情API实例
	m_funcCreator = (CTPCreator)DLLHelper::get_symbol(m_hInstCTP, creatorName);
	m_pUserAPI = m_funcCreator(path.c_str(), false, false);
	m_pUserAPI->RegisterSpi(this);
	m_pUserAPI->RegisterFront((char*)m_strFrontAddr.c_str());

	return true;
}

void ParserCTPOpt::release()
{
	disconnect();
}

bool ParserCTPOpt::connect()
{
	if(m_pUserAPI)
	{
		m_pUserAPI->Init();
	}

	return true;
}

bool ParserCTPOpt::disconnect()
{
	if(m_pUserAPI)
	{
		m_pUserAPI->RegisterSpi(NULL);
		m_pUserAPI->Release();
		m_pUserAPI = NULL;
	}

	return true;
}

void ParserCTPOpt::OnRspError( CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast )
{
	IsErrorRspInfo(pRspInfo);
}

void ParserCTPOpt::OnFrontConnected()
{
	if(m_sink)
	{
		write_log(m_sink, LL_INFO, "[ParserCTPOpt] Market data server connected");
		m_sink->handleEvent(WPE_Connect, 0);
	}

	// 连接成功后自动发起登录请求
	ReqUserLogin();
}

void ParserCTPOpt::OnRspUserLogin( CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast )
{
	if(bIsLast && !IsErrorRspInfo(pRspInfo))
	{
		// 获取交易日期
		m_uTradingDate = strtoul(m_pUserAPI->GetTradingDay(), NULL, 10);
		
		if(m_sink)
		{
			m_sink->handleEvent(WPE_Login, 0);
		}

		// 登录成功后自动订阅期权行情
		SubscribeMarketData();
	}
}

void ParserCTPOpt::OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if(m_sink)
	{
		m_sink->handleEvent(WPE_Logout, 0);
	}
}

void ParserCTPOpt::OnFrontDisconnected( int nReason )
{
	if(m_sink)
	{
		write_log(m_sink, LL_ERROR, "[ParserCTPOpt] Market data server disconnected: {}", nReason);
		m_sink->handleEvent(WPE_Close, 0);
	}
}

void ParserCTPOpt::OnRspUnSubMarketData( CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast )
{
	// 期权行情退订响应处理（暂未实现具体逻辑）
}

void ParserCTPOpt::OnRtnDepthMarketData( CThostFtdcDepthMarketDataField *pDepthMarketData )
{	
	if(m_pBaseDataMgr == NULL)
	{
		return;
	}

	// 时间处理：支持本地时间和服务器时间两种模式
	uint32_t actDate, actTime;
	if (m_bLocalTime)
	{
		// 使用本地时间
		TimeUtils::getDateTime(actDate, actTime);
	}
	else
	{
		// 使用服务器时间，需要处理期权夜盘跨日问题
		actDate = strtoul(pDepthMarketData->ActionDay, NULL, 10);
		actTime = strToTime(pDepthMarketData->UpdateTime) * 1000 + pDepthMarketData->UpdateMillisec;
	}
	uint32_t actHour = actTime / 10000000;

	// 期权夜盘时间处理：防止时间跨日导致的问题
	if (actDate == m_uTradingDate && actHour >= 20)
	{
		// 如果是夜盘时间且在当日，可能为夜盘时间，需要进行不能单纯交给数据接收端
		// 这里需要手动校验一下
		uint32_t curDate, curTime;
		TimeUtils::getDateTime(curDate, curTime);
		uint32_t curHour = curTime / 10000000;

		// 如果现在是凌晨后，收到的是昨天12点前的行情数据，有可能会产生错误配对，导致收到异常数据
		// 所以这里直接丢弃
		if (curHour >= 3 && curHour < 9)
			return;

		actDate = curDate;

		// 处理期权夜盘时间跨日的边界情况
		if (actHour == 23 && curHour == 0)
		{
			// 行情时间晚于系统时间
			actDate = TimeUtils::getNextDate(curDate, -1);
		}
		else if (actHour == 0 && curHour == 23)
		{
			// 系统时间晚于行情时间
			actDate = TimeUtils::getNextDate(curDate, 1);
		}
	}

	// 根据期权合约代码和交易所查找合约信息
	WTSContractInfo* cInfo = m_pBaseDataMgr->getContract(pDepthMarketData->InstrumentID, pDepthMarketData->ExchangeID);
	if (cInfo == NULL)
		return;

	WTSCommodityInfo* pCommInfo = cInfo->getCommInfo();

	// 创建期权Tick数据对象
	WTSTickData* tick = WTSTickData::create(pDepthMarketData->InstrumentID);
	tick->setContractInfo(cInfo);
	WTSTickStruct& quote = tick->getTickStruct();
	strcpy(quote.exchg, pCommInfo->getExchg());
	
	// 设置时间信息（期权特殊处理：确保使用有效日期）
	quote.action_date = actDate != 0 ? actDate : m_uTradingDate;
	quote.action_time = actTime;
	
	// 设置期权价格信息
	quote.price = checkValid(pDepthMarketData->LastPrice);
	quote.open = checkValid(pDepthMarketData->OpenPrice);
	quote.high = checkValid(pDepthMarketData->HighestPrice);
	quote.low = checkValid(pDepthMarketData->LowestPrice);
	quote.total_volume = pDepthMarketData->Volume;
	quote.trading_date = m_uTradingDate;
	
	// 期权结算价处理
	if(pDepthMarketData->SettlementPrice != DBL_MAX)
		quote.settle_price = checkValid(pDepthMarketData->SettlementPrice);
	
	// 期权成交额处理：郑商所需要特殊处理
	if(strcmp(quote.exchg, "CZCE") == 0)
	{
		quote.total_turnover = pDepthMarketData->Turnover*pCommInfo->getVolScale();
	}
	else
	{
		if(pDepthMarketData->Turnover != DBL_MAX)
			quote.total_turnover = pDepthMarketData->Turnover;
	}

	// 期权持仓量
	quote.open_interest = (uint32_t)pDepthMarketData->OpenInterest;

	// 期权涨跌停价格
	quote.upper_limit = checkValid(pDepthMarketData->UpperLimitPrice);
	quote.lower_limit = checkValid(pDepthMarketData->LowerLimitPrice);

	// 期权昨收盘、昨结算、昨持仓
	quote.pre_close = checkValid(pDepthMarketData->PreClosePrice);
	quote.pre_settle = checkValid(pDepthMarketData->PreSettlementPrice);
	quote.pre_interest = (uint32_t)pDepthMarketData->PreOpenInterest;

	// 期权委卖价格（五档）
	quote.ask_prices[0] = checkValid(pDepthMarketData->AskPrice1);
	quote.ask_prices[1] = checkValid(pDepthMarketData->AskPrice2);
	quote.ask_prices[2] = checkValid(pDepthMarketData->AskPrice3);
	quote.ask_prices[3] = checkValid(pDepthMarketData->AskPrice4);
	quote.ask_prices[4] = checkValid(pDepthMarketData->AskPrice5);

	// 期权委买价格（五档）
	quote.bid_prices[0] = checkValid(pDepthMarketData->BidPrice1);
	quote.bid_prices[1] = checkValid(pDepthMarketData->BidPrice2);
	quote.bid_prices[2] = checkValid(pDepthMarketData->BidPrice3);
	quote.bid_prices[3] = checkValid(pDepthMarketData->BidPrice4);
	quote.bid_prices[4] = checkValid(pDepthMarketData->BidPrice5);

	// 期权委卖量（五档）
	quote.ask_qty[0] = pDepthMarketData->AskVolume1;
	quote.ask_qty[1] = pDepthMarketData->AskVolume2;
	quote.ask_qty[2] = pDepthMarketData->AskVolume3;
	quote.ask_qty[3] = pDepthMarketData->AskVolume4;
	quote.ask_qty[4] = pDepthMarketData->AskVolume5;

	// 期权委买量（五档）
	quote.bid_qty[0] = pDepthMarketData->BidVolume1;
	quote.bid_qty[1] = pDepthMarketData->BidVolume2;
	quote.bid_qty[2] = pDepthMarketData->BidVolume3;
	quote.bid_qty[3] = pDepthMarketData->BidVolume4;
	quote.bid_qty[4] = pDepthMarketData->BidVolume5;

	// 将处理好的期权Tick数据发送给上层应用
	if(m_sink)
		m_sink->handleQuote(tick, 1);

	tick->release();
}

void ParserCTPOpt::OnRspSubMarketData( CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast )
{
	if(!IsErrorRspInfo(pRspInfo))
	{
		// 期权订阅成功（暂未实现具体逻辑）
	}
	else
	{
		// 期权订阅失败（暂未实现具体逻辑）
	}
}

void ParserCTPOpt::OnHeartBeatWarning( int nTimeLapse )
{
	if (m_sink)
		write_log(m_sink, LL_INFO, "[ParserCTPOpt] Heartbeating, elapse: {}", nTimeLapse);
}

void ParserCTPOpt::ReqUserLogin()
{
	if(m_pUserAPI == NULL)
	{
		return;
	}

	// 构造登录请求
	CThostFtdcReqUserLoginField req;
	memset(&req, 0, sizeof(req));
	strcpy(req.BrokerID, m_strBroker.c_str());
	strcpy(req.UserID, m_strUserID.c_str());
	strcpy(req.Password, m_strPassword.c_str());
	
	// 发送登录请求
	int iResult = m_pUserAPI->ReqUserLogin(&req, ++m_iRequestID);
	if(iResult != 0)
	{
		if(m_sink)
			write_log(m_sink, LL_ERROR, "[ParserCTPOpt] Sending login request failed: {}", iResult);
	}
}

void ParserCTPOpt::SubscribeMarketData()
{
	CodeSet codeFilter = m_filterSubs;
	if(codeFilter.empty())
	{
		// 如果没有指定订阅列表，则返回（不订阅全部期权合约列表）
		return;
	}

	// 构造订阅期权合约数组
	char ** subscribe = new char*[codeFilter.size()];
	int nCount = 0;
	for(auto& code : codeFilter)
	{
		// 处理期权合约代码格式：移除交易所前缀
		std::size_t pos = code.find('.');
		if (pos != std::string::npos)
			subscribe[nCount++] = (char*)code.c_str() + pos + 1;
		else
			subscribe[nCount++] = (char*)code.c_str();
	}

	// 发送期权行情订阅请求
	if(m_pUserAPI && nCount > 0)
	{
		int iResult = m_pUserAPI->SubscribeMarketData(subscribe, nCount);
		if (iResult != 0)
		{
			if (m_sink)
				write_log(m_sink, LL_ERROR, "[ParserCTPOpt] Sending md subscribe request failed: {}", iResult);
		}
		else
		{
			if (m_sink)
				write_log(m_sink, LL_INFO, "[ParserCTPOpt] Market data of {} contracts subscribed in total", nCount);
		}
	}
	codeFilter.clear();
	delete[] subscribe;
}

bool ParserCTPOpt::IsErrorRspInfo(CThostFtdcRspInfoField *pRspInfo)
{
	// 简化的错误检查实现（总是返回false）
	// 实际应用中应该检查pRspInfo->ErrorID是否为0
	return false;
}

void ParserCTPOpt::subscribe(const CodeSet &vecSymbols)
{
	if(m_uTradingDate == 0)
	{
		// 如果尚未登录，先保存期权订阅列表
		m_filterSubs = vecSymbols;
	}
	else
	{
		// 如果已经登录，立即执行期权订阅
		m_filterSubs = vecSymbols;
		char * subscribe[500] = {NULL};
		int nCount = 0;
		for (auto& code  : vecSymbols)
		{
			// 处理期权合约代码格式：移除交易所前缀
			std::size_t pos = code.find('.');
			if (pos != std::string::npos)
				subscribe[nCount++] = (char*)code.c_str() + pos + 1;
			else
				subscribe[nCount++] = (char*)code.c_str();
		}

		// 发送期权行情订阅请求
		if(m_pUserAPI && nCount > 0)
		{
			int iResult = m_pUserAPI->SubscribeMarketData(subscribe, nCount);
			if (iResult != 0)
			{
				if (m_sink)
					write_log(m_sink, LL_ERROR, "[ParserCTPOpt] Sending md subscribe request failed: {}", iResult);
			}
			else
			{
				if (m_sink)
					write_log(m_sink, LL_INFO, "[ParserCTPOpt] Market data of {} contracts subscribed in total", nCount);
			}
		}
	}
}

void ParserCTPOpt::unsubscribe(const CodeSet &vecSymbols)
{
	// 期权退订功能暂未实现
}

bool ParserCTPOpt::isConnected()
{
	return m_pUserAPI!=NULL;
}

void ParserCTPOpt::registerSpi(IParserSpi* listener)
{
	m_sink = listener;

	if(m_sink)
		m_pBaseDataMgr = m_sink->getBaseDataMgr();
}